{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import numpy as np\n",
    "from numpy import linalg as la\n",
    "from sklearn import preprocessing as pre\n",
    "import random\n",
    "import math\n",
    "from numpy import ma"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_label_matrix(X):\n",
    "\n",
    "    '''\n",
    "    Target 1: choose the front 20% data of each class as labeled sample\n",
    "    Target 2: rearrange all the points and let the front l points be labeled\n",
    "    '''\n",
    "    \n",
    "    return X,Yl,l"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def classify(X,Yl,c,num_of_adaptive_neighbours=9):\n",
    "    \n",
    "    '''\n",
    "    X=[X1,X2,...,Xv]  --list of feature matrixes\n",
    "    Yl --labale matrix\n",
    "    '''\n",
    "\n",
    "    #Standardlize:\n",
    "    n,_=X[0].shape\n",
    "    v=len(X)#v:number of different views\n",
    "    for i in range(v):\n",
    "        X[i]=pre.scale(X[i],axis=1)#You need to import sklearn.preprocessing as pre before using the standardlization module.\n",
    "    print(\"Preprocession finished...\")\n",
    "    \n",
    "    #Initialize:\n",
    "    lambda_=random.randint(1,30)\n",
    "    l=Yl.shape[0]#l denotes the number of labeled points\n",
    "    u=n-l#u denoted the number of unlabeled points\n",
    "    W=np.ones((v),dtype=np.float32)/v#W records the weight of each view\n",
    "    alpha=np.zeros((n),dtype=np.float32)\n",
    "    S=np.zeros((n,n),dtype=np.float32)#S denotes the similarity matrix\n",
    "    Dist=np.zeros((n,n),dtype=np.float32)#Dist denotes the distance matrix\n",
    "    F=np.zeros((n,c),dtype=np.float32)#F denotes the indicator matrix\n",
    "    F[:l]=Yl\n",
    "    k_=num_of_adaptive_neighbours\n",
    "    for i in range(n):\n",
    "        for j in range(n):\n",
    "            for k in range(v):\n",
    "                Dist[i][j]+=W[k]*(la.norm(X[k][i,:]-X[k][j,:]))**2\n",
    "        ascending_order_index=np.argsort(Dist[i])[1:k_+1]\n",
    "        dist_of_neighbours_sorted_ascending=Dist[i][ascending_order_index]\n",
    "        alpha[i]=0.5*(k_*dist_of_neighbours_sorted_ascending[k_-1]-np.sum(dist_of_neighbours_sorted_ascending))\n",
    "        S[i][ascending_order_index]=(np.mean(dist_of_neighbours_sorted_ascending))/alpha[i]*0.5+1/k_\n",
    "        S[i][ascending_order_index]=S[i][ascending_order_index]-dist_of_neighbours_sorted_ascending/alpha[i]*0.5\n",
    "    mean_alpha=np.mean(alpha)\n",
    "    S=np.maximum(S,0)\n",
    "    \n",
    "    result=0\n",
    "    for k in range(v):\n",
    "        a=0\n",
    "        for i in range(n):\n",
    "            for j in range(n):\n",
    "                a+=S[i][j]*(la.norm(X[k][i]-X[k][j]))**2\n",
    "        result+=a**0.5\n",
    "    result+=mean_alpha*(la.norm(S))**2\n",
    "    print('After initialization, the objective value is %f.'%result)\n",
    "    \n",
    "    #Update:\n",
    "    for iter_num in range(30):\n",
    "        #Update W_v:\n",
    "        for k in range(v):\n",
    "            tmp=0\n",
    "            for i in range(n):\n",
    "                for j in range(n):\n",
    "                    tmp+=S[i][j]*((la.norm(X[k][i]-X[k][j]))**2)\n",
    "            W[k]=0.5/(tmp**0.5)\n",
    "        #Update F:\n",
    "        diagonal_element=(np.sum(S,axis=1)+np.sum(S.T,axis=1))*0.5\n",
    "        D_s=np.zeros((n,n),dtype=np.float32)#D_s denotes the degree matrix\n",
    "        for i in range(n):\n",
    "            D_s[i][i]=diagonal_element[i]\n",
    "        L_s=D_s-(S+S.T)/2 #L_s denotes Laplacian matrix\n",
    "        F[l:]=-np.dot(np.dot(la.inv(L_s[u:,l:]),L_s[u:,:l]),Yl)\n",
    "        #Update S:\n",
    "        S=np.zeros((n,n),dtype=np.float32)\n",
    "        for i in range(n):\n",
    "            for j in range(n):\n",
    "                Dist[i][j]=0\n",
    "                Dist[i][j]+=lambda_*la.norm(F[i,:]-F[j,:])**2 \n",
    "                for k in range(v):\n",
    "                    Dist[i][j]+=W[k]*(la.norm(X[k][i,:]-X[k][j,:]))**2\n",
    "            ascending_order_index=np.argsort(Dist[i])[1:k_+1]\n",
    "            dist_of_neighbours_sorted_ascending=Dist[i][ascending_order_index]\n",
    "            alpha[i]=0.5*(k_*dist_of_neighbours_sorted_ascending[k_-1]-np.sum(dist_of_neighbours_sorted_ascending))\n",
    "            S[i][ascending_order_index]=(np.mean(dist_of_neighbours_sorted_ascending))/alpha[i]*0.5+1/k_\n",
    "            S[i][ascending_order_index]=S[i][ascending_order_index]-dist_of_neighbours_sorted_ascending/alpha[i]*0.5\n",
    "        mean_alpha=np.mean(alpha)\n",
    "        S=np.maximum(S,0)\n",
    "        \n",
    "        #Compute the objective value:\n",
    "        result=0\n",
    "        for k in range(v):\n",
    "            a=0\n",
    "            for i in range(n):\n",
    "                for j in range(n):\n",
    "                    a+=S[i][j]*(la.norm(X[k][i]-X[k][j]))**2\n",
    "            result+=a**0.5\n",
    "        result+=mean_alpha*(la.norm(S))**2\n",
    "        print('After iteration %i,'%(iter_num+1),end='')\n",
    "        print(' the objective value is %f.'%result)\n",
    "        \n",
    "    return F"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
